#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <iostream>

using namespace std;

#define BUFFER_SIZE 1024

// p操作和v操作
void sem_p(int semid,int semnum){
    struct sembuf sp={
        .sem_num=semnum,
        .sem_op=-1,
        .sem_flg=SEM_UNDO
    };
    semop(semid,&sp,1);
}
void sem_v(int semid,int semnum){
    struct sembuf sv={
        .sem_num=semnum,
        .sem_op=+1,
        .sem_flg=SEM_UNDO
    };
    semop(semid,&sv,1);
}

struct sharedData{
    char buffer[BUFFER_SIZE];
    int in;
    int out;
};
union semun{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};
int main(){
    key_t key=ftok("./semserver.cc",0x6666);
    if(key<0){
        perror("fotk error");
        exit(1);
    }
    // 创建信号量集，2个信号量
    // 0号信号量为互斥信号量
    // 1号信号量为同步信号量
    int semid=semget(key,3,IPC_CREAT | 0666);
    if(semid<0){
        perror("semget error");
        exit(2);
    }
    // 初始化信号量
    // union semun{
    //     int val; // 信号量值 SETVAL操作信号量个数
    //     struct semid_ds *buf; // 信号量集信息 IPC_STAT和IPC_SET操作信号量集
    //     unsigned short *array; // 信号量数组 GETALL、SETALL操作所有信号量时
    //     struct seminfo *__buf; // 信号量集信息
    // };
    union semun arg;
    arg.val=1;
    // 0号信号量为互斥信号量，初始值为1
    semctl(semid,0,SETVAL,arg);
    // 1号信号量为同步信号量，初始值为0
    arg.val=0;
    semctl(semid,1,SETVAL,arg);
    // 2号信号量为资源的数量，初始值为10
    arg.val=BUFFER_SIZE;
    semctl(semid,2,SETVAL,arg);

    key_t shmkey=ftok("./semserver.cc",0x6666);
    if(shmkey<0){
        perror("shmftok error");
        exit(2);
    }
    int shmid=shmget(shmkey,1024,IPC_CREAT | 0666);
    if(shmid<0){
        perror("shmget error");
        exit(3);
    }
    sharedData* sd=(sharedData*)shmat(shmid,NULL,0);
    if(sd==(void*)-1){
        perror("shmat error");
        exit(4);
    }
    sd->in=0;
    sd->out=0;
    pid_t pid=fork();
    if(pid<0){
        perror("fork error");
        exit(5);
    }else if(pid==0){
        //子进程
        for(int i=0;i<10;++i){
            sem_p(semid,2);
            sem_p(semid,0);
            sd->buffer[sd->in]='a'+i%26;
            sd->in=(sd->in+1)%BUFFER_SIZE;
            sem_v(semid,0);
            sem_v(semid,1);
            sleep(1);
        }
        exit(6);
    }else{
        //父进程
        while(1){
            sem_p(semid,1);
            sem_p(semid,0);
            cout<<"consumer: "<<sd->buffer[sd->out]<<endl;
            sd->out=(sd->out+1)%BUFFER_SIZE;
            sem_v(semid,0);
            sem_v(semid,2);
            sleep(1);
        }

    }

    shmdt(sd);
    shmctl(shmid,IPC_RMID,NULL);
    // 删除信号量
    semctl(semid,0,IPC_RMID);
    semctl(semid,1,IPC_RMID);
    semctl(semid,2,IPC_RMID);
    return 0;
}